_Pragma("once")

#include "tool.hpp"

#include <memory>
#include <list>
#include <iostream>

namespace sdl_engine::unit_test {

#define TEST_TRUE(s) do { if (!(s)) std::cout << #s " Test True Failed!" << std::endl; } while(0);
#define TEST_FALSE(s) do { if ((s)) std::cout << #s " Test False Faild!" << std::endl; } while(0);

class Fixture {
public:
    virtual ~Fixture() = default;

    virtual void SetUp() = 0;
    virtual void TearDown() = 0;
};

class Test {
public:
    virtual ~Test() = default;

    virtual void SetUp() {}
    virtual void Run() = 0;
    virtual void TearDown() {}
};

class UnitTest final {
public:
    using TestLambda = std::function<void(void)>;
    inline void RegistFixture(Fixture* fixture) {
        fixtures_.push_back(std::unique_ptr<Fixture>(fixture));
    }
    inline void RegistTest(Test* test) {
        tests_.push_back(std::unique_ptr<Test>(test));
    }

    inline void AddTest(Test* test) {
        testinfos_.push_back({test, nullptr, nullptr});
    }

    inline void AddTest(TestLambda test) {
        testinfos_.push_back({nullptr, test, nullptr});
    }

    inline void AddTest(TestLambda test, Fixture* fixture) {
        testinfos_.push_back({nullptr, test, fixture});
    }

    inline void AddTest(Test* test, Fixture* fixture) {
        testinfos_.push_back({test, nullptr, fixture});
    }

    void RunTests();

private:
    struct TestInfo {
        Test* test;
        TestLambda lambda;
        Fixture* fixture;
    };
    std::list<TestInfo> testinfos_;
    std::list<Unique<Test>> tests_;
    std::list<Unique<Fixture>> fixtures_;
};

extern UnitTest unittest;

}
